package com.ks.winterwarmimage.mqtt.service;

import android.annotation.SuppressLint;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Build;
import android.os.Bundle;
import android.os.IBinder;
import android.os.PowerManager;

import androidx.localbroadcastmanager.content.LocalBroadcastManager;

import org.eclipse.paho.client.mqttv3.DisconnectedBufferOptions;
import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
import org.eclipse.paho.client.mqttv3.IMqttMessageListener;
import org.eclipse.paho.client.mqttv3.MqttClientPersistence;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.eclipse.paho.client.mqttv3.MqttPersistenceException;
import org.eclipse.paho.client.mqttv3.MqttSecurityException;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * <p>
 * 与MQTT客户端实现进行交互的Android服务
 * </p>
 * <p>
 * MqttService的主要API旨在尽可能地反映IMqttAsyncClient，并根据Android环境进行适当调整。
 * 这些调整通常包括在每个方法中添加两个参数：-
 * </p>
 * <ul>
 * <li>invocationContext - 从应用程序传递的字符串，用于识别操作上下文（主要为支持JavaScript API实现）</li>
 * <li>activityToken - 从Activity传递的字符串，用于关联回调方法或其他上下文特定数据</li>
 * </ul>
 * <p>
 * 为了支持多个客户端连接，大部分MQTT工作被委托给MqttConnection对象。这些对象由“客户端句柄”字符串标识，这是Activity和更高级别API引用它们的方式。
 * </p>
 * <p>
 * 使用此服务的Activity应启动并绑定到它，使用BIND_AUTO_CREATE标志。此服务的生命周期基于此方法。
 * </p>
 * <p>
 * 操作高度异步 - 在大多数情况下，结果通过广播一个（或偶尔多个）适当的Intents返回给Activity，
 * Activity需要注册一个监听器。Intents具有一个Action，即
 * {@link MqttServiceConstants#CALLBACK_TO_ACTIVITY
 * MqttServiceConstants.CALLBACK_TO_ACTIVITY}，允许Activity使用适当的IntentFilter注册监听器。
 * 进一步的数据由Intent中的“额外数据”提供，如下所示：-
 * </p>
 *<table border="1" summary="">
 * <tr>
 * <th align="left">名称</th>
 * <th align="left">数据类型</th>
 * <th align="left">值</th>
 * <th align="left">用于的操作</th>
 * </tr>
 * <tr>
 * <td align="left" valign="top">
 * {@link MqttServiceConstants#CALLBACK_CLIENT_HANDLE
 * MqttServiceConstants.CALLBACK_CLIENT_HANDLE}</td>
 * <td align="left" valign="top">String</td>
 * <td align="left" valign="top">标识发起此操作的客户端的clientHandle</td>
 * <td align="left" valign="top">所有操作</td>
 * </tr>
 * <tr>
 * <td align="left" valign="top">{@link MqttServiceConstants#CALLBACK_STATUS
 * MqttServiceConstants.CALLBACK_STATUS}</td>
 * <td align="left" valign="top">Serializable</td>
 * <td align="left" valign="top">表示操作成功与否的{@link Status}值</td>
 * <td align="left" valign="top">所有操作</td>
 * </tr>
 * <tr>
 * <td align="left" valign="top">
 * {@link MqttServiceConstants#CALLBACK_ACTIVITY_TOKEN
 * MqttServiceConstants.CALLBACK_ACTIVITY_TOKEN}</td>
 * <td align="left" valign="top">String</td>
 * <td align="left" valign="top">传递到操作中的activityToken</td>
 * <td align="left" valign="top">所有操作</td>
 * </tr>
 * <tr>
 * <td align="left" valign="top">
 * {@link MqttServiceConstants#CALLBACK_INVOCATION_CONTEXT
 * MqttServiceConstants.CALLBACK_INVOCATION_CONTEXT}</td>
 * <td align="left" valign="top">String</td>
 * <td align="left" valign="top">传递到操作中的invocationContext</td>
 * <td align="left" valign="top">所有操作</td>
 * </tr>
 * <tr>
 * <td align="left" valign="top">{@link MqttServiceConstants#CALLBACK_ACTION MqttServiceConstants.CALLBACK_ACTION}</td>
 * <td align="left" valign="top">String</td>
 * <td align="left" valign="top">其中之一
 * *<table summary="">
 * <tr>
 * <td align="left" valign="top"> {@link MqttServiceConstants#SEND_ACTION MqttServiceConstants.SEND_ACTION}</td>
 * </tr>
 * <tr>
 * <td align="left" valign="top">
 * {@link MqttServiceConstants#UNSUBSCRIBE_ACTION MqttServiceConstants.UNSUBSCRIBE_ACTION}</td>
 * </tr>
 *  <tr>
 *  <td align="left" valign="top"> {@link MqttServiceConstants#SUBSCRIBE_ACTION MqttServiceConstants.SUBSCRIBE_ACTION}</td>
 * </tr>
 * <tr>
 * <td align="left" valign="top"> {@link MqttServiceConstants#DISCONNECT_ACTION MqttServiceConstants.DISCONNECT_ACTION}</td>
 * </tr>
 * <tr>
 * <td align="left" valign="top"> {@link MqttServiceConstants#CONNECT_ACTION  MqttServiceConstants.CONNECT_ACTION}</td>
 * </tr>
 * <tr>
 * <td align="left" valign="top">
 * {@link MqttServiceConstants#MESSAGE_ARRIVED_ACTION MqttServiceConstants.MESSAGE_ARRIVED_ACTION}</td>
 * </tr>
 * <tr>
 * <td align="left" valign="top">
 * {@link MqttServiceConstants#MESSAGE_DELIVERED_ACTION MqttServiceConstants.MESSAGE_DELIVERED_ACTION}</td>
 * </tr>
 * <tr>
 * <td align="left" valign="top">
 * {@link MqttServiceConstants#ON_CONNECTION_LOST_ACTION MqttServiceConstants.ON_CONNECTION_LOST_ACTION}</td>
 * </tr>
 * </table>
 * </td>
 * <td align="left" valign="top">所有操作</td>
 * </tr>
 * <tr>
 * <td align="left" valign="top">
 * {@link MqttServiceConstants#CALLBACK_ERROR_MESSAGE MqttServiceConstants.CALLBACK_ERROR_MESSAGE}
 * <td align="left" valign="top">String</td>
 * <td align="left" valign="top">适当的错误消息（尽可能取自相关异常）</td>
 * <td align="left" valign="top">所有失败的操作</td>
 * </tr>
 * <tr>
 * <td align="left" valign="top">
 * {@link MqttServiceConstants#CALLBACK_ERROR_NUMBER MqttServiceConstants.CALLBACK_ERROR_NUMBER}
 * <td align="left" valign="top">int</td>
 * <td align="left" valign="top">适当的错误代码（尽可能取自相关异常）</td>
 * <td align="left" valign="top">所有失败的操作</td>
 * </tr>
 * <tr>
 * <td align="left" valign="top">
 * {@link MqttServiceConstants#CALLBACK_EXCEPTION_STACK MqttServiceConstants.CALLBACK_EXCEPTION_STACK}</td>
 * <td align="left" valign="top">String</td>
 * <td align="left" valign="top">失败调用的堆栈争用</td>
 * <td align="left" valign="top">连接丢失事件</td>
 * </tr>
 * <tr>
 * <td align="left" valign="top">
 * {@link MqttServiceConstants#CALLBACK_MESSAGE_ID MqttServiceConstants.CALLBACK_MESSAGE_ID}</td>
 * <td align="left" valign="top">String</td>
 * <td align="left" valign="top">消息存储中消息的标识符，由“活动”用来确认消息的到达，以便服务可以将其从存储中删除</td>
 * <td align="left" valign="top">消息到达事件</td>
 * </tr>
 * <tr>
 * <td align="left" valign="top">
 * {@link MqttServiceConstants#CALLBACK_DESTINATION_NAME
 * MqttServiceConstants.CALLBACK_DESTINATION_NAME}
 * <td align="left" valign="top">String</td>
 * <td align="left" valign="top">接收消息的主题</td>
 * <td align="left" valign="top">消息到达事件</td>
 * </tr>
 * <tr>
 * <td align="left" valign="top">
 * {@link MqttServiceConstants#CALLBACK_MESSAGE_PARCEL
 * MqttServiceConstants.CALLBACK_MESSAGE_PARCEL}</td>
 * <td align="left" valign="top">Parcelable</td>
 * <td align="left" valign="top">新消息以Android Parcelable格式封装为{@link ParcelableMqttMessage}</td>
 * <td align="left" valign="top">消息到达事件</td>
 * </tr>
 * </table>
 */
@SuppressLint("Registered")
public class MqttService extends Service implements MqttTraceHandler {

    // 意图、日志消息等的标识符
    static final String TAG = "MqttService";

    // 用于对Activity进行跟踪回调的回调id需要由activity酌情设置
    private String traceCallbackId;
    //追踪状态
    private boolean traceEnabled = false;

    // 将接收到的消息保存到某个位置，直到我们确定它们已到达应用程序
    MessageStore messageStore;

    // 处理网络连接变化的意向接收器
    private NetworkConnectionIntentReceiver networkConnectionMonitor;

    //识别用户何时更改“背景数据”偏好的接收器，以及跟踪该偏好的标志
    // 只有在android版本ICE_CREAM_SANDWICH以下才真正相关-请参阅android文档
    private BackgroundDataPreferenceReceiver backgroundDataPreferenceMonitor;
    private volatile boolean backgroundDataEnabled = true;

    // 一种让自己回到活动中的方式
    private MqttServiceBinder mqttServiceBinder;

    // 从客户端句柄字符串到实际客户端连接的映射。
    private Map<String/* clientHandle */, MqttConnection/* client */> connections = new ConcurrentHashMap<>();

    public MqttService() {
        super();
    }

    /**
     * 通过构建合适的Intent对象并广播数据，将数据传回Activity
     *
     * @param clientHandle 数据来源
     * @param status OK 或 Error
     * @param dataBundle 要传递的数据
     */
    void callbackToActivity(String clientHandle, Status status,
                            Bundle dataBundle) {
        // Don't call traceDebug, as it will try to callbackToActivity leading
        // to recursion.
        Intent callbackIntent = new Intent(
                MqttServiceConstants.CALLBACK_TO_ACTIVITY);
        if (clientHandle != null) {
            callbackIntent.putExtra(
                    MqttServiceConstants.CALLBACK_CLIENT_HANDLE, clientHandle);
        }
        callbackIntent.putExtra(MqttServiceConstants.CALLBACK_STATUS, status);
        if (dataBundle != null) {
            callbackIntent.putExtras(dataBundle);
        }
        LocalBroadcastManager.getInstance(this).sendBroadcast(callbackIntent);
    }

    // API的主要实现如下:-

    /**
     * 获取一个MqttConnection对象以表示与服务器的连接
     *
     * @param serverURI 指定用于连接到MQTT服务器的协议、主机名和端口
     * @param clientId 指定用于标识与服务器的此连接的名称
     * @param contextId 指定应用程序上下文信息以区分应用程序
     * @param persistence 指定要与此客户端一起使用的持久层
     * @return “活动”用作此MqttConnection的“句柄”的字符串
     */
    public String getClient(String serverURI, String clientId, String contextId, MqttClientPersistence persistence) {
        String clientHandle = serverURI + ":" + clientId+":"+contextId;
        if (!connections.containsKey(clientHandle)) {
            MqttConnection client = new MqttConnection(this, serverURI,
                    clientId, persistence, clientHandle);
            connections.put(clientHandle, client);
        }
        return clientHandle;
    }

    /**
     * 连接到特定客户端指定的MQTT服务器
     *
     * @param clientHandle 确定要使用的MqttConnection
     * @param connectOptions 要使用的MQTT连接选项
     * @param invocationContext 要传递回应用程序的任意数据
     * @param activityToken 要传回活动的任意标识符
     * @throws MqttSecurityException 如果存在安全异常则引发
     * @throws MqttException 为所有其他MqttException引发
     */
    public void connect(String clientHandle, MqttConnectOptions connectOptions,
                        String invocationContext, String activityToken)
            throws MqttSecurityException, MqttException {
        MqttConnection client = getConnection(clientHandle);
        client.connect(connectOptions, null, activityToken);

    }

    /**
     * 请求所有客户端在适当的情况下重新连接
     */
    void reconnect() {
        traceDebug(TAG, "Reconnect to server, client size=" + connections.size());
        for (MqttConnection client : connections.values()) {
            traceDebug("Reconnect Client:",
                    client.getClientId() + '/' + client.getServerURI());
            if(this.isOnline()){
                client.reconnect();
            }
        }
    }

    /**
     * 关闭来自特定客户端的连接
     *
     * @param clientHandle 确定要使用的MqttConnection
     */
    public void close(String clientHandle) {
        MqttConnection client = getConnection(clientHandle);
        client.close();
    }

    /**
     * 断开与服务器的连接
     *
     * @param clientHandle 确定要使用的MqttConnection
     * @param invocationContext 要传递回应用程序的任意数据
     * @param activityToken  要传回活动的任意标识符
     */
    public void disconnect(String clientHandle, String invocationContext,
                           String activityToken) {
        MqttConnection client = getConnection(clientHandle);
        client.disconnect(invocationContext, activityToken);
        connections.remove(clientHandle);


        // 活动已完成使用我们，因此我们可以停止服务
        // 活动与BIND_AUTO_CREATE绑定，因此服务将一直保留，直到最后一个活动断开连接
        stopSelf();
    }

    /**
     * 断开与服务器的连接
     *
     * @param clientHandle  确定要使用的MqttConnection
     * @param quiesceTimeout 以毫秒为单位
     * @param invocationContext 要传递回应用程序的任意数据
     * @param activityToken 要传回活动的任意标识符
     */
    public void disconnect(String clientHandle, long quiesceTimeout,
                           String invocationContext, String activityToken) {
        MqttConnection client = getConnection(clientHandle);
        client.disconnect(quiesceTimeout, invocationContext, activityToken);
        connections.remove(clientHandle);

        // 活动已完成使用我们，因此我们可以停止服务
        // 活动与BIND_AUTO_CREATE绑定，因此服务将一直保留，直到最后一个活动断开连接
        stopSelf();
    }

    /**
     * 获取特定客户端的状态
     *
     * @param clientHandle 确定要使用的MqttConnection
     * @return 如果指定的客户端连接到MQTT服务器，则为true
     */
    public boolean isConnected(String clientHandle) {
        MqttConnection client = getConnection(clientHandle);
        if(client!=null)
            return client.isConnected();
        else
            return false;
    }

    /**
     * 将消息发布到主题
     *
     * @param clientHandle 确定要使用的MqttConnection
     * @param topic 要发布的主题
     * @param payload  要发布的消息的内容
     * @param qos 所要求的服务质量
     * @param retained MQTT服务器是否应保留此消息
     * @param invocationContext 要传递回应用程序的任意数据
     * @param activityToken 要传回活动的任意标识符
     * @throws MqttPersistenceException 当存储消息出现问题时
     * @throws MqttException 如果发布消息时出错
     * @return 用于跟踪操作的令牌
     */
    public IMqttDeliveryToken publish(String clientHandle, String topic,
                                      byte[] payload, int qos, boolean retained,
                                      String invocationContext, String activityToken)
            throws MqttPersistenceException, MqttException {
        MqttConnection client = getConnection(clientHandle);
        return client.publish(topic, payload, qos, retained, invocationContext,
                activityToken);
    }

    /**
     * 将消息发布到主题
     *
     * @param clientHandle 确定要使用的MqttConnection
     * @param topic 要发布的主题
     * @param message 要发布的消息
     * @param invocationContext  要传递回应用程序的任意数据
     * @param activityToken  要传回活动的任意标识符
     * @throws MqttPersistenceException 当存储消息出现问题时
     * @throws MqttException 如果发布消息时出错
     * @return 用于跟踪操作的令牌
     */
    public IMqttDeliveryToken publish(String clientHandle, String topic,
                                      MqttMessage message, String invocationContext, String activityToken)
            throws MqttPersistenceException, MqttException {
        MqttConnection client = getConnection(clientHandle);
        return client.publish(topic, message, invocationContext, activityToken);
    }

    /**
     * 订阅主题
     *
     * @param clientHandle 确定要使用的MqttConnection
     * @param topic 一个可能不加修饰的主题名称
     * @param qos 要求的主题服务质量
     * @param invocationContext 要传递回应用程序的任意数据
     * @param activityToken 要传回活动的任意标识符
     */
    public void subscribe(String clientHandle, String topic, int qos,
                          String invocationContext, String activityToken) {
        MqttConnection client = getConnection(clientHandle);
        client.subscribe(topic, qos, invocationContext, activityToken);
    }

    /**
     * 订阅一个或多个主题
     *
     * @param clientHandle 确定要使用的MqttConnection
     * @param topic 可能带有通配符的主题名称列表
     * @param qos 要求的每个主题的服务质量
     * @param invocationContext 要传递回应用程序的任意数据
     * @param activityToken  要传回活动的任意标识符
     */
    public void subscribe(String clientHandle, String[] topic, int[] qos,
                          String invocationContext, String activityToken) {
        MqttConnection client = getConnection(clientHandle);
        client.subscribe(topic, qos, invocationContext, activityToken);
    }

    /**
     * 使用主题筛选器订阅
     *
     * @param clientHandle 确定要使用的MqttConnection
     * @param topicFilters 可能带有通配符的主题筛选器列表
     * @param qos 要求的每个主题的服务质量
     * @param invocationContext 要传递回应用程序的任意数据
     * @param activityToken  要传回活动的任意标识符
     * @param messageListeners 用于处理传入消息的回调
     */
    public void subscribe(String clientHandle, String[] topicFilters, int[] qos, String invocationContext, String activityToken, IMqttMessageListener[] messageListeners){
        MqttConnection client = getConnection(clientHandle);
        client.subscribe(topicFilters, qos, invocationContext, activityToken, messageListeners);
    }

    /**
     * 取消订阅某个主题
     *
     * @param clientHandle Mqtt连接标识
     * @param topic 一个可能不加修饰的主题名称
     * @param invocationContext 要传递回应用程序的任意数据
     * @param activityToken 要传回活动的任意标识符
     */
    public void unsubscribe(String clientHandle, final String topic,
                            String invocationContext, String activityToken) {
        MqttConnection client = getConnection(clientHandle);
        client.unsubscribe(topic, invocationContext, activityToken);
    }

    /**
     * 取消订阅一个或多个主题
     *
     * @param clientHandle Mqtt连接标识
     * @param topic 可能带有通配符的主题名称列表
     * @param invocationContext 要传递回应用程序的任意数据
     * @param activityToken 要传回活动的任意标识符
     */
    public void unsubscribe(String clientHandle, final String[] topic,
                            String invocationContext, String activityToken) {
        MqttConnection client = getConnection(clientHandle);
        client.unsubscribe(topic, invocationContext, activityToken);
    }

    /**
     * 为客户端获取所有未完成交付的令牌
     *
     * @param clientHandle  Mqtt连接标识
     * @return 令牌数组（可能为空）
     */
    public IMqttDeliveryToken[] getPendingDeliveryTokens(String clientHandle) {
        MqttConnection client = getConnection(clientHandle);
        return client.getPendingDeliveryTokens();
    }

    /**
     * 获取此客户端句柄标识的MqttConnection
     *
     * @param clientHandle Mqtt连接标识
     * @return 此句柄标识的MqttConnection
     */
    private MqttConnection getConnection(String clientHandle) {
        MqttConnection client = connections.get(clientHandle);
      //  if (client == null) {
       //     throw new IllegalArgumentException("Invalid ClientHandle");
       // }
        return client;
    }

    /**
     * 当消息已传递回应用程序时由活动调用
     *
     * @param clientHandle 接收消息的客户端的标识符
     * @param id MQTT消息的标识符
     * @return {@link Status}
     */
    public Status acknowledgeMessageArrival(String clientHandle, String id) {
        if (messageStore.discardArrived(clientHandle, id)) {
            return Status.OK;
        }
        else {
            return Status.ERROR;
        }
    }

    // 扩展服务

    /**
     * @see Service#onCreate()
     */
    @Override
    public void onCreate() {
        super.onCreate();

        // 创建一个绑定器，该绑定器将允许活动UI向服务发送命令
        mqttServiceBinder = new MqttServiceBinder(this);

        // 创建一个缓冲接收到的消息的位置，直到我们知道这些消息已传递给应用程序
        messageStore = new DatabaseMessageStore(this, this);
    }



    /**
     * @see Service#onDestroy()
     */
    @Override
    public void onDestroy() {
        // 立即断开连接
        for (MqttConnection client : connections.values()) {
            client.disconnect(null, null);
        }

        // 清除
        if (mqttServiceBinder != null) {
            mqttServiceBinder = null;
        }

        unregisterBroadcastReceivers();

        if (this.messageStore !=null )
            this.messageStore.close();

        super.onDestroy();
    }

    /**
     * @see Service#onBind(Intent)
     */
    @Override
    public IBinder onBind(Intent intent) {
        // 我们在绑定时传递回活动的内容-对我们自己的引用，以及开始时给我们的activityToken
        String activityToken = intent
                .getStringExtra(MqttServiceConstants.CALLBACK_ACTIVITY_TOKEN);
        mqttServiceBinder.setActivityToken(activityToken);
        return mqttServiceBinder;
    }

    /**
     * @see Service#onStartCommand(Intent,int,int)
     */
    @Override
    public int onStartCommand(final Intent intent, int flags, final int startId) {
        // 运行到明确停止，进程重新启动时重新启动
        registerBroadcastReceivers();

        return START_STICKY;
    }

    /**
     * 确定在对“活动”进行跟踪调用时要传递的callbackId
     *
     * @param traceCallbackId 回调到“活动”中的标识符
     */
    public void setTraceCallbackId(String traceCallbackId) {
        this.traceCallbackId = traceCallbackId;
    }

    /**
     * 打开和关闭跟踪
     *
     * @param traceEnabled 设置 <code>true</code>可打开跟踪，设置<code>false</code>可关闭跟踪
     */
    public void setTraceEnabled(boolean traceEnabled) {
        this.traceEnabled = traceEnabled;
    }

    /**
     * 检查跟踪是否打开或关闭。
     *
     * @return 痕迹的状态
     */
    public boolean isTraceEnabled(){
        return this.traceEnabled;
    }

    /**
     * 跟踪调试信息
     *
     * @param tag 跟踪源的标识符
     * @param message 要跟踪的文本
     */
    @Override
    public void traceDebug(String tag, String message) {
        traceCallback(MqttServiceConstants.TRACE_DEBUG, tag, message);
    }

    /**
     * 跟踪错误信息
     *
     * @param tag  跟踪源的标识符
     * @param message  要跟踪的文本
     */
    @Override
    public void traceError(String tag, String message) {
        traceCallback(MqttServiceConstants.TRACE_ERROR, tag, message);
    }

    private void traceCallback(String severity, String tag, String message) {
        if ((traceCallbackId != null) && (traceEnabled)) {
            Bundle dataBundle = new Bundle();
            dataBundle.putString(MqttServiceConstants.CALLBACK_ACTION, MqttServiceConstants.TRACE_ACTION);
            dataBundle.putString(MqttServiceConstants.CALLBACK_TRACE_SEVERITY, severity);
            dataBundle.putString(MqttServiceConstants.CALLBACK_TRACE_TAG, tag);
            //dataBundle.putString(MqttServiceConstants.CALLBACK_TRACE_ID, traceCallbackId);
            dataBundle.putString(MqttServiceConstants.CALLBACK_ERROR_MESSAGE, message);
            callbackToActivity(traceCallbackId, Status.ERROR, dataBundle);
        }
    }

    /**
     * 跟踪异常
     *
     * @param tag 跟踪源的标识符
     * @param message 要跟踪的文本
     * @param e 例外
     */
    @Override
    public void traceException(String tag, String message, Exception e) {
        if (traceCallbackId != null) {
            Bundle dataBundle = new Bundle();
            dataBundle.putString(MqttServiceConstants.CALLBACK_ACTION, MqttServiceConstants.TRACE_ACTION);
            dataBundle.putString(MqttServiceConstants.CALLBACK_TRACE_SEVERITY, MqttServiceConstants.TRACE_EXCEPTION);
            dataBundle.putString(MqttServiceConstants.CALLBACK_ERROR_MESSAGE,  message);
            dataBundle.putSerializable(MqttServiceConstants.CALLBACK_EXCEPTION, e); //TODO: Check
            dataBundle.putString(MqttServiceConstants.CALLBACK_TRACE_TAG, tag);
            //dataBundle.putString(MqttServiceConstants.CALLBACK_TRACE_ID, traceCallbackId);
            callbackToActivity(traceCallbackId, Status.ERROR, dataBundle);
        }
    }

    @SuppressWarnings("deprecation")
    private void registerBroadcastReceivers() {
        if (networkConnectionMonitor == null) {
            networkConnectionMonitor = new NetworkConnectionIntentReceiver();
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                registerReceiver(networkConnectionMonitor, new IntentFilter(
                        ConnectivityManager.CONNECTIVITY_ACTION),RECEIVER_EXPORTED);
            }else {
                registerReceiver(networkConnectionMonitor, new IntentFilter(
                        ConnectivityManager.CONNECTIVITY_ACTION));
            }
        }

        if (Build.VERSION.SDK_INT <Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
            // 支持旧系统的后台数据首选项
            ConnectivityManager cm = (ConnectivityManager) getSystemService(CONNECTIVITY_SERVICE);
            backgroundDataEnabled = cm.getBackgroundDataSetting();
            if (backgroundDataPreferenceMonitor == null) {
                backgroundDataPreferenceMonitor = new BackgroundDataPreferenceReceiver();
                registerReceiver(backgroundDataPreferenceMonitor,
                        new IntentFilter(ConnectivityManager.ACTION_BACKGROUND_DATA_SETTING_CHANGED));
            }
        }else{
            if (backgroundDataPreferenceMonitor == null) {
                backgroundDataPreferenceMonitor = new BackgroundDataPreferenceReceiver();
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                    registerReceiver(backgroundDataPreferenceMonitor,new IntentFilter(
                                    ConnectivityManager.ACTION_BACKGROUND_DATA_SETTING_CHANGED),RECEIVER_EXPORTED);
                }else{
                    registerReceiver(backgroundDataPreferenceMonitor, new IntentFilter(
                                    ConnectivityManager.ACTION_BACKGROUND_DATA_SETTING_CHANGED));
                }
            }
        }
    }

    private void unregisterBroadcastReceivers(){
        if(networkConnectionMonitor != null){
            unregisterReceiver(networkConnectionMonitor);
            networkConnectionMonitor = null;
        }

        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
            if(backgroundDataPreferenceMonitor != null){
                unregisterReceiver(backgroundDataPreferenceMonitor);
            }
        }
    }

    /**
     * 响应网络连接的更改而调用-在失去与服务器的连接后，这允许我们等待，直到我们再次获得可用的数据连接
     */
    private class NetworkConnectionIntentReceiver extends BroadcastReceiver {

        @Override
        @SuppressLint("Wakelock")
        public void onReceive(Context context, Intent intent) {
            traceDebug(TAG, "Internal network status receive.");
            // 我们通过请求唤醒锁来防止手机关机——我们请求尽可能少的唤醒锁——刚好足以让CPU运行到完成
            PowerManager pm = (PowerManager) getSystemService(POWER_SERVICE);
            @SuppressLint("InvalidWakeLockTag")
            PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "MQTT");
            wl.acquire();
            traceDebug(TAG,"Reconnect for Network recovery.");
            if (isOnline()) {
                traceDebug(TAG,"Online,reconnect.");
                // 我们有网络连接-再试一次连接
                reconnect();
            } else {
                notifyClientsOffline();
            }

            wl.release();
        }
    }

    /**
     * @return android服务是否可以被视为在线
     */
    public boolean isOnline() {
        ConnectivityManager cm = (ConnectivityManager) getSystemService(CONNECTIVITY_SERVICE);
         NetworkInfo networkInfo = cm.getActiveNetworkInfo();
        //noinspection RedundantIfStatement
        if (networkInfo != null
                && networkInfo.isAvailable()
                && networkInfo.isConnected()
                && backgroundDataEnabled) {
            return true;
        }

        return false;
    }

    /**
     * 通知客户端我们处于脱机状态
     */
    private void notifyClientsOffline() {
        for (MqttConnection connection : connections.values()) {
            connection.offline();
        }
    }

    /**
     * 检测“允许背景数据”设置的更改-仅在ICE_CREAM_SANDWICH以下使用
     */
    private class BackgroundDataPreferenceReceiver extends BroadcastReceiver {

        @SuppressWarnings("deprecation")
        @Override
        public void onReceive(Context context, Intent intent) {
            ConnectivityManager cm = (ConnectivityManager) getSystemService(CONNECTIVITY_SERVICE);
            traceDebug(TAG,"Reconnect since BroadcastReceiver.");
            if (cm.getBackgroundDataSetting()) {
                if (!backgroundDataEnabled) {
                    backgroundDataEnabled = true;
                    // 我们有互联网连接-请再试一次连接
                    reconnect();
                }
            } else {
                backgroundDataEnabled = false;
                notifyClientsOffline();
            }
        }
    }

    /**
     * 设置此客户端的DisconnectedBufferOptions
     * @param clientHandle 客户端的标识符
     * @param bufferOpts 此客户端的DisconnectedBufferOptions
     */
    public void setBufferOpts(String clientHandle, DisconnectedBufferOptions bufferOpts) {
        MqttConnection client = getConnection(clientHandle);
        client.setBufferOpts(bufferOpts);
    }

    public int getBufferedMessageCount(String clientHandle){
        MqttConnection client = getConnection(clientHandle);
        return client.getBufferedMessageCount();
    }

    public MqttMessage getBufferedMessage(String clientHandle, int bufferIndex){
        MqttConnection client = getConnection(clientHandle);
        return client.getBufferedMessage(bufferIndex);
    }

    public void deleteBufferedMessage(String clientHandle, int bufferIndex){
        MqttConnection client = getConnection(clientHandle);
        client.deleteBufferedMessage(bufferIndex);
    }

}